/*
微信商户付款，用户提现操作
@Time : 2019/2/28 0028 14:41
@Author : visons
*/

package transfers

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"gitee.com/visons/gopkg/logger"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

type WxConf struct {
	KEY   string //商户平台设置的密钥key
	MchID string //商户id
	Appid string //商户账号appid
}

//微信支付商户证书证书位置
type CertificatePath struct {
	WechatCertPath string //证书pem格式（apiclient_cert.pem）
	WechatKeyPath  string //证书密钥pem格式（apiclient_key.pem）
	WechatCAPath   string //CA证书（rootca.pem）
}

type Withdraw struct {
	config WxConf
	client http.Client
}

// NewClient returns a *Client ready to use.
func NewWithdraw(wxcfg WxConf, ce CertificatePath) (*Withdraw, error) {
	tlsConfig, err := getTLSConfig(ce.WechatCertPath, ce.WechatKeyPath, ce.WechatCAPath)
	if err != nil {
		return nil, err
	}
	tr := &http.Transport{TLSClientConfig: tlsConfig}
	tlsClient := http.Client{Transport: tr}

	client := &Withdraw{
		config: wxcfg,
		client: tlsClient,
	}
	return client, nil
}

//企业付款给个人用户
func (w *Withdraw) PaymentToUser(amount int64, openid, partnerTradeNo, desc, clientIp string) (*PaymentToUserRes, error) {
	order := PaymentToUserReq{}
	order.MchAppid = w.config.Appid
	order.Mchid = w.config.MchID
	order.Openid = openid
	order.Amount = amount
	order.Desc = desc
	order.PartnerTradeNo = partnerTradeNo
	order.CheckName = "NO_CHECK" //NO_CHECK：不校验真实姓名 FORCE_CHECK：强校验真实姓名
	order.SpbillCreateIp = clientIp
	order.NonceStr = GetRandomString()
	//获取签名
	sign := w.md5Signature(order)
	logger.Info("PaymentToUser sing: %s", sign)
	order.Sign = sign

	//发送请求
	xmlBody, _ := xml.MarshalIndent(order, " ", " ")
	resp, err := w.client.Post(order.Url(), "application/xml", bytes.NewBuffer(xmlBody))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	bodyByte, _ := ioutil.ReadAll(resp.Body)
	var rsp PaymentToUserRes
	xmlerr := xml.Unmarshal(bodyByte, &rsp)
	logger.Info("PaymentToUserRes %s", string(bodyByte))
	if xmlerr != nil {
		return nil, xmlerr
	}

	if rsp.ReturnCode != "SUCCESS" {
		return nil, fmt.Errorf("return code %s, return msg %s", rsp.ReturnCode, rsp.ReturnMsg)
	}

	if rsp.ResultCode != "SUCCESS" {
		return nil, fmt.Errorf("err code %s, err code desc %s", rsp.ErrCode, rsp.ErrCodeDes)
	}

	return &rsp, nil
}

//md5签名
func (t *Withdraw) md5Signature(order PaymentToUserReq) string {
	o := url.Values{}
	o.Add("mch_appid", order.MchAppid)
	o.Add("mchid", order.Mchid)
	//o.Add("device_info", order.DeviceInfo)
	o.Add("partner_trade_no", order.PartnerTradeNo)
	o.Add("check_name", order.CheckName)
	o.Add("amount", strconv.FormatInt(order.Amount, 10))
	o.Add("spbill_create_ip", order.SpbillCreateIp)
	o.Add("desc", order.Desc)
	o.Add("nonce_str", order.NonceStr)
	o.Add("openid", order.Openid)
	r, _ := url.QueryUnescape(o.Encode())
	logger.Info("signature param :%s", r)
	//使用md5加密
	sign := Md5([]byte(r + "&key=" + t.config.KEY))
	sign = strings.ToUpper(sign)
	return sign
}
